import { proxyRefs } from "../reactivity";
import { emit } from "./componentEmit";
import { initProps } from "./componentProps"
import { PublicInstanceProxyHandlers } from "./componentPublicInstance"
import { initSlots } from "./componentSlots";

export function createComponentInstance(vnode,parent) {
    const component = {
        vnode,
        type:vnode.type,
        setupState:{},
        props:{},
        next:null,
        component:null,
        emit:() =>{},
        slots:{},
        provides:parent ? parent.provides : {},
        parent,
        isMounted:false,
        subTree:{}
    }
    //  emit.bind(null,component)这一步操作就是默认第一个参数为component，用户不需要去传
    component.emit = emit.bind(null,component) as any
    return component
}

export function setupComponent(instance) {
    // TODO 
    initProps(instance,instance.vnode.props) 
    initSlots(instance,instance.vnode.children) 
    setupStatefulComponent(instance)
}

function setupStatefulComponent(instance: any) {
    const Component = instance.type
    // 往实例身上添加proxy代理
    instance.proxy = new Proxy({_:instance},PublicInstanceProxyHandlers)

    const { setup } = Component
    if(setup) {
        setCurrentInstance(instance)
        const setupResult = setup(instance.props,{
            emit:instance.emit
        })
        // 重置currentInstance
        setCurrentInstance(null)
        handleSetupResult(instance,setupResult)
    }
}

function handleSetupResult(instance: any,setupResult: any) {
    // setupResult可能为 function object
    if(typeof setupResult === 'object') {
        instance.setupState = proxyRefs(setupResult)
    }
    finishComponentSetup(instance)
}

function finishComponentSetup(instance: any) {
    const Component = instance.type
    if(complier && !Component.render) {
        if(Component.template) {
            Component.render = complier(Component.template)
        }
    }
    // template
    instance.render = Component.render
}

let currentInstance = null

export function getCurrentInstance() {
    return currentInstance
}

export function setCurrentInstance(instance) {
    currentInstance = instance
}

let complier
export function registerRuntimeCompiler(_complier) {
    complier = _complier
}
